package cn.skyclass.net
{
	import cn.skyclass.events.EventNotification;
	import cn.skyclass.events.LoadEvent;
	import cn.skyclass.events.WsEvent;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import mx.collections.ArrayCollection;
	
	[Event(name="change", type="flash.events.Event")]
	[Event(name="loaded", type="cn.skyclass.events.LoadEvent")]
	[Event(name="loading", type="cn.skyclass.events.LoadEvent")]
	[Event(name="failed", type="cn.skyclass.events.LoadEvent")]	
	[Event(name="canceled", type="cn.skyclass.events.LoadEvent")]	
	/**
	 * 基本的数据加载类，完成各种的数据加载工作，并完成简单的数据处理
	 */
	[Bindable]
	public class BaseLoader extends EventDispatcher
	{
		/**
		 * 保存数据加载的结果列表，一般是原始的 beans list
		 */
		public var resultList:ArrayCollection = new ArrayCollection();
		
		/**
		 * 用于结果数据显示的列表，其每一个值是对 resultList 中对应数据的显示包装。
		 * 如果提供，则要求一一对应，完全同步。
		 * 或者不提供显示列表，则此属性为空集合。
		 */
		public var showerList:ArrayCollection = new ArrayCollection();


		/**
		 * 是否正在数据加载中
		 */
		private var _loading:Boolean;
		public function get loading():Boolean{
			return this._loading;
		}
		public function set loading(value:Boolean):void{
			this._loading = value;
		}
		
		/**
		 * 数据是否已加载完毕
		 */
		private var _loaded:Boolean;
		public function get loaded():Boolean{
			return this._loaded;
		}
		public function set loaded(value:Boolean):void{
			this._loaded = value;
		}		
		
		
		/**
		 * 当前已加载的数据是否已经过期
		 */
		private var _dataExpired:Boolean;
		protected function get dataExpired():Boolean{
			return this._dataExpired;
		}
		protected function set dataExpired(value:Boolean):void{
			this._dataExpired = value;
		}	
		
		/**
		 * 执行数据加载工作
		 */
		public function load():void{
			if(this.tryDispatchLoadedEvent()){ return; }
			this.dispatchLoadingEvent();
			this.doLoad();
		}
		
		protected function doLoad():void{
			// for overriding
		}
		
		/**
		 * 重新加载当前的数据
		 */
		public function reload():void{
			this.dataExpired = true;
			this.reset();
			this.load();
		}		
		
		/**
		 * 将加载器重置为初始状态，包括清除所有已经加载的数据
		 */
		protected function reset():void{
			this.resultList = new ArrayCollection();
			this.showerList = new ArrayCollection();
			this.dataExpired = false;
			this.loading = false;
			this.loaded = false;
		}
		
		/**
		 * 加载数据后对列表进行排序处理
		 */
		protected function sort():void{	
			// for overriding
		}
		
		/**
		 * 加载数据后对结果列表进行验证处理工作
		 */
		protected function validate():void{	
			// for overriding
		}
		
		/**
		 * 尝试发布数据已加载事件，发布成功后返回 true，否则返回 false
		 */
		protected function tryDispatchLoadedEvent():Boolean{
			if(this.dataExpired){
				this.reset(); return false;
			}else if(this.loaded){
				this.dispatchLoadedEvent(); return true;
			}else if(this.loading){
				return true;
			}else{
				return false;
			}
		}
		
		
		/**
		 * 用于发布和监听与此操作相关的全局事件
		 * 使用默认的 EventNotification
		 */
		protected function get en():EventNotification{
			return EventNotification.getInstance();
		}
		
		/**
		 * 发布正在加载数据的事件
		 */
		protected function dispatchLoadingEvent(e:Event=null):void{
			this.loading = true;
			dispatchEvent(new LoadEvent(LoadEvent.LOADING));			
		}
		
		/**
		 * 发布数据加载完毕事件
		 */
		protected function dispatchLoadedEvent(e:Event=null):void{
			this.loaded = true;
			this.loading = false;
			this.dataExpired = false;
			
			var we:WsEvent = e as WsEvent;
			if(we != null){
				this.resultList = we.beansCollection;
			}
			dispatchEvent(new LoadEvent(LoadEvent.LOADED));
		}
		
		/**
		 * 发布数据加载失败事件
		 */
		protected function dispatchFailedEvent(e:Event=null):void{
			this.loaded = false;
			this.loading = false;
			dispatchEvent(new LoadEvent(LoadEvent.FAILED));
		}	
			
		/**
		 * 发布取消事件
		 */
		protected function dispatchCanceledEvent(e:Event=null):void{
			this.loaded = false;
			this.loading = false;
			dispatchEvent(new LoadEvent(LoadEvent.CANCELED));
		}		
		
		/**
		 * 发布数据改变时的事件
		 */
		protected function dispatchChangeEvent(e:Event=null):void{
			dispatchEvent(new Event(Event.CHANGE));			
		}		
	}
}